#pragma once
#include<iostream>
#include<queue>
#include"Cond.hpp"
#include"Log.hpp"
#include"Task.hpp"
#include"Thread.hpp"
#include"Mutex.hpp"


//一下的线程池实则是按照生产者消费者模型进行构建的
namespace ThreadPoolModule
{
    using namespace MutexModule;  //这个里面放置的是线程锁（互斥）相关的代码
    using namespace CondModule;  //这个里面放置的是条件变量（同步）相关的代码
    using namespace LogModule;   //这个里面放置的是日志代码
    using namespace ThreadModule; //这个里面放着的是线程的封装代码
    static const int _grac = 5; //这个是线程池中工作的线程的个数
    template<class T>
    class ThreadPool
    {
        void WakeOnethread()  //唤醒一个线程
        {
            _cond.Signal();
            LOG(LogLeval :: INFO) << "线程唤醒成功";
        }

        void WakeAllthread() //唤醒所有的线程
        {
            LockGurd(_mutex);
            if(_issleeping == 0) return; 
            _cond.Brodcast();
            LOG(LogLeval :: INFO) << "所有线程唤醒成功";
        }

        void HardHeader()
        {
            char name[128];
            pthread_getname_np(pthread_self(),name,sizeof(name));
            while(1)
            {
                T t; //定义一个任务对象
                {
                    LockGurd s1(_mutex);  //因为访问临街资源，所以直接上锁吧
                    //1.队列为空 ；2.线程正在启动
                    while(_task.empty() && _isrunning)
                    {
                        _issleeping++; //睡觉的线程个数加一
                        _cond.Wait(_mutex);
                        _issleeping--;
                    }
                    if(_task.empty() && !_isrunning)
                    {
                        LOG(LogLeval :: INFO) << name << "退出了，线程池退出&&线程池为空";
                        break;
                    }
                    t = _task.front();
                    _task.pop();
                }
                t();
            }
        }


    public:
        ThreadPool(int grac = _grac)
        :_num(grac),
        _isrunning(false)
        {
            for(int i = 0 ; i < _num; i++)
            {
                _thread.emplace_back(
                    [this]
                    {
                        HardHeader(); //进行回调函数的调用，让它自己回调
                    }
                );
            }
        }

        void Start()
        {
            if(_isrunning)
            return;  //如果已经运行了那就没必要在继续启动了
            _isrunning = true;
            for(auto& e : _thread)
            {
                e.Start();
                LOG(LogLeval :: DEBUG) << "start new thread success: " << e.GetName();
            }
        }

        void Stop()
        {
            if(_issleeping) return; //如果没有睡眠的就不需要下面的操作
            WakeAllthread(); //唤醒所有的线程，让他们完成他们的工作才能暂停
        }


        void Excueue(const T& in)  //发布任务的
        {
            if(_isrunning)
            {
                LockGurd(_mutex);
                _task.push(im);
                if(_num == _issleeping)  
                {
                    WakeOnethread();  //线程全部睡觉的话就侥幸
                }
            }
        }

        void Join()
        {
            for(auto e : _thread)
            {
                e.Join();  //让每个线程进行等待，避免数据的消失
            }
        }
    private:
        std :: vector<T> _thread; //把线程池中的线程管理一下
        int _num; //记录线程池中线程的个数
        std :: queue<T> _task; //存放任务的队列
        Cond _cond; //让线程进行同步的
        Mutex _mutex; //为了线程互斥的
        bool _isrunning; //线程是否启动
        int _issleeping = 0; //线程休眠的个数
    };
}